package shared

import "github.com/spf13/viper"

// The public member is shared within entire application.
var ConfigService AppConfigService

// This is an example of the data structure for config file.
// The structure is very complicated you might want to get the value via key.
type AppConfig struct {
	DataSource struct {
		Dsn string
	}

	Jwt struct {
		SigningKey string
		Expiration int64
	}

	Server struct {
		RouteRootGroupName string
	}
}

// Provides public methods to interact with config file.
type AppConfigService interface {
	GetString(key string) string
	GetInt(key string) int
	GetBool(key string) bool
	GetAllSettings() map[string]interface{}
	GetAppConfig() AppConfig
}

// Creates the instance of appConfigService.
// It is called by Init function.
// It loads the config file during initialization.
func NewAppConfigService() AppConfigService {
	var appConfig AppConfig

	// Sets the config file path.
	viper.SetConfigFile("./conf/application.yaml")

	// Reads the config file. The data can be retrieved via functions like viper.GetString(key).
	viper.ReadInConfig()

	// Unmarshal the config data to structure type.
	// This is another way you can access the config data.
	viper.Unmarshal(&appConfig)

	return appConfigService{appConfig: appConfig}
}

// GetString returns the value associated with the key as a string.
// The nested key is supported. Example: dataSource.dsn.
func (this appConfigService) GetString(key string) string {
	return viper.GetString(key)
}

// GetInt returns the value associated with the key as an integer.
// The nested key is supported. Example: dataSource.dsn.
func (this appConfigService) GetInt(key string) int {
	return viper.GetInt(key)
}

// GetBool returns the value associated with the key as a boolean.
// The nested key is supported. Example: dataSource.dsn.
func (this appConfigService) GetBool(key string) bool {
	return viper.GetBool(key)
}

// AllSettings merges all settings and returns them as a map[string]interface{}.
func (this appConfigService) GetAllSettings() map[string]interface{} {
	return viper.AllSettings()
}

// GetAppConfig returns the data structure of AppConfig.
func (this appConfigService) GetAppConfig() AppConfig {
	return this.appConfig
}

type appConfigService struct {
	// The private member used to store the loaded config data.
	appConfig AppConfig
}
